/*
        Updater For Java Programs 
        
    Copyright (C) 2010, Arttu Viljakainen 
    Published under GNU General Public License V3 
    (see http://www.gnu.org/licenses/licenses.html)
    
    This file is part of Updater For Java Programs.

    Updater For Java Programs is free software: 
    you can redistribute it and/or modify it under the terms of the GNU General 
    Public License as published by the Free Software Foundation, 
    either version 3 of the License, or (at your option) any later version.

    Updater For Java Programs is distributed in the hope that it will be useful, 
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General 
    Public License for more details.

    You should have received a copy of the GNU General Public License
    along with Updater for Java Programs. If not, see         
    <http://www.gnu.org/licenses/>.
 */
package updater.gui;


import java.awt.BorderLayout;
import java.awt.Desktop;
import java.awt.Dimension;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JProgressBar;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.SwingUtilities;
import javax.swing.border.TitledBorder;

import updater.control.FileDownloader;
import updater.control.UpdateController;
import updater.listener.UpdateListener;



public class Updater extends JFrame implements PropertyChangeListener {
    
    private String newFileName = "temp"; //todo
    private String oldFileName = "";
    private String updateURL = "";
    
    private FileDownloader updateDownloader;
    private UpdateController updateController;
    private UpdateListener updateListener;

    private JProgressBar progressBar;
    
    private JPanel masterContainer;
    private JTextArea statusArea;
    private JButton startUpdateButton;
    private JButton cancelButton;
    private JButton finishedButton;
    private JPanel buttonsPanel;
    private JButton exitButton;
    
    private JButton startApplication;
    
    private UpdateStatus status;
    
    public Updater() {
        setSize(new Dimension(400, 300));
        setDefaultCloseOperation(DISPOSE_ON_CLOSE);
        setTitle("Updater");
        buildGUI();
        setVisible(true);
        status = UpdateStatus.NOT_STARTED;
        readParameters();
    }
        
    private void readParameters() {
        String arg1 = null;
        String arg2 = null;
        BufferedReader parametersReader = null;
        
        try {
        	System.out.println("!");
            File updateParameters = new File("update_parameters.tmp");
            parametersReader = new BufferedReader(new FileReader(updateParameters));    
            arg1 = parametersReader.readLine();
            arg2 = parametersReader.readLine();
        } catch(Exception e) {
//            e.printStackTrace();
        } finally {
            try {
                parametersReader.close();
            }catch(Exception e) {
//                e.printStackTrace();
            }
        }
        
        if(arg1 != null && arg2 != null) {
            oldFileName = arg1;
            updateURL = arg2;
        } else {
            errorInUpdate("Could not find the update_parameters.tmp file.");
        }
    }
    
    private void buildGUI() {
        updateController = new UpdateController(this);
        updateListener = new UpdateListener(updateController);

        statusArea = new JTextArea();
        statusArea.setPreferredSize(new Dimension(200, 200));
        statusArea.setEditable(false);
        
        startUpdateButton = new JButton("Start update");
        startUpdateButton.addActionListener(updateListener);
        
        cancelButton = new JButton("Cancel");
        cancelButton.addActionListener(updateListener);
        
        startApplication = new JButton("Start application");
        startApplication.addActionListener(updateListener);
        
        finishedButton = new JButton("Finished");
        finishedButton.addActionListener(updateListener);
        
        exitButton = new JButton("Exit");
        exitButton.addActionListener(updateListener);
        
        masterContainer = new JPanel(new BorderLayout());
        
        progressBar = new JProgressBar(0, 100);
        JPanel progressViews = new JPanel();
        progressViews.setLayout(new BorderLayout());
        
        progressViews.add(new JScrollPane(statusArea), BorderLayout.CENTER);
        progressViews.add(progressBar, BorderLayout.SOUTH);
        progressViews.setBorder(new TitledBorder("Progress"));
        masterContainer.add(progressViews, BorderLayout.CENTER);
        
        buttonsPanel = new JPanel();
        buttonsPanel.add(startApplication);
        buttonsPanel.add(startUpdateButton);
        buttonsPanel.add(cancelButton);
        
        masterContainer.add(buttonsPanel, BorderLayout.SOUTH);
        
        add(masterContainer);
        pack();
    }
    
    public void updateFile() {
        showCancelButton();
        repaint();
        updateDownloader = new FileDownloader(updateURL, newFileName); 
        updateDownloader.addPropertyChangeListener(this);
        status = UpdateStatus.DOWNLOADING;
        updateDownloader.execute();
    }
    
    public void finishUpdate() {

        if(status == UpdateStatus.FINISHED) {
            Desktop desktop = Desktop.getDesktop();
            File updatedFiresoft = new File(oldFileName);
            
            try {
                desktop.open(updatedFiresoft);
            } catch(IOException ioe) {
                ioe.printStackTrace();
                
            }
        }
        
        System.exit(0);

    }
    
    @Override
    public void propertyChange(PropertyChangeEvent evt) {
        
        System.out.println("Download status: " + evt.getNewValue());
        if ("progress".equals(evt.getPropertyName())) {
            progressBar.setValue((Integer)evt.getNewValue());
        }
        if(evt.getNewValue().toString().equals("DONE")) {
            if(status == UpdateStatus.DOWNLOADING) {
                status = UpdateStatus.REPLACING;
                replaceOldFileWithNew();
                status = UpdateStatus.FINISHED;
                showFinishedButton();
            } else {
                showFinishedButton();
            }
        }
        
    }
    
    public void replaceOldFileWithNew() {
        
        System.out.println("Starting update");
        publishStatus("Trying to activate new file...");
        
        File fileToBeMoved = new File(newFileName); 
        System.out.println(fileToBeMoved.exists());
        File destination = new File(oldFileName);
        destination.delete();
        System.out.println(destination.exists());
        boolean success = fileToBeMoved.renameTo(new File(oldFileName));
        if(!success) {
            System.out.println("Failed to replace file " + oldFileName + " with " + newFileName + "!");
            publishStatus("Failed to replace file " + oldFileName + " with " + newFileName + "!");
        } else {
            System.out.println("Replaced file");
            publishStatus("Activated new file.");
        }
        
    }
    
    private void showCancelButton() {
        buttonsPanel.removeAll();
        buttonsPanel.add(cancelButton);
        repaint();
        setVisible(true);
    }
    
    private void showFinishedButton() {
        buttonsPanel.removeAll();
        buttonsPanel.add(finishedButton);
        repaint();
        setVisible(true);
    }
    
    private void showExitButton() {
        buttonsPanel.removeAll();
        buttonsPanel.add(exitButton);
        repaint();
        setVisible(true);
    }

    public void cancelUpdate() {
        
        if(status == UpdateStatus.FINISHED) {
            publishStatus("Update has already been done!");
        } else if(status == UpdateStatus.NOT_STARTED) {
            publishStatus("Cancelling");
            exit();
        } else {
            status = UpdateStatus.CANCEL;
            
            publishStatus("Cancelling update!");

            updateDownloader.cancelUpdate();
            updateDownloader.cancel(true);
            
            File destination = new File(newFileName);
            if(destination.exists()) {
                if(destination.canWrite()) {
                    if(destination.delete() == false) {
                        publishStatus("You may need to remove temp file " + newFileName + " yourself.");
                    }
                } else {
                    publishStatus("You may need to remove temp file " + newFileName + " yourself.");
                }
            }
            
            destination.delete();
    
            publishStatus("Update cancelled");
        }
    }
    
    public void publishStatus(String status) {
        statusArea.setText(statusArea.getText() + status + "\n");
    }
    
    private void errorInUpdate(String error) {
        status = UpdateStatus.ERROR;
        publishStatus("Problems during the update:\n" + error);
        showExitButton();
    }
    
    public void exit() {
        System.exit(0);
    }
    
    static String arg1 = "";
    static String arg2 = "";
    
    public static void main(String[] args) {        
               
        if(args.length > 2) {
            arg1 = args[1];
            arg2 = args[2];
            
        } else { // For testing purposes
        
            SwingUtilities.invokeLater(new Runnable() {
                public void run() {
                    new Updater();
                }
            });
        }

    }


}
